home *** CD-ROM | disk | FTP | other *** search
- /* OS- and machine-dependent stuff for IBM-PC running MS-DOS and Turbo-C
- * Copyright 1991 Phil Karn, KA9Q
- *
- * XMS extensions Copyright 1993 Johan. K. Reinalda, WG7J
- */
- #include <dir.h>
- #include <dos.h>
- #include <io.h>
- #include <conio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <process.h>
- #include <fcntl.h>
- #include <alloc.h>
- #include <stdarg.h>
- #include <bios.h>
- #include <time.h>
- #include "global.h"
- #include "mbuf.h"
- #include "proc.h"
- #include "iface.h"
- #include "internet.h"
- #include "session.h"
- #include "tty.h"
- #include "usock.h"
- #include "socket.h"
- #include "smtp.h"
- #include "cmdparse.h"
- #include "dirutil.h"
- #include "files.h"
- #include "pc.h"
- #include "index.h"
- #include "mailbox.h"
- #ifdef EMS
- #include "memlib.h"
- #endif
- #ifdef XMS
- #include "xms.h"
- #endif
-
- #define CTLC 0x3
- #define DEL 0x7f
-
- static int kbchar __ARGS((void));
- extern int Curdisp;
- extern struct proc *Display;
- FILE *Rawterm;
- /* Highest i've ever seen in 'ps' is around 400, ie 800 bytes - WG7J */
- unsigned _stklen = 2048;
- volatile int Tick;
- static int32 Starttime;
- int32 Clock;
-
- #ifdef MULTITASK
- int Background;
- int Nokeys;
- extern unsigned Minheap;
- #endif
- extern int Tracesession;
-
- #ifdef SPLITSCREEN
- extern char MainColors;
- extern char SplitColors;
- #endif
- #ifdef STATUSWIN
- extern int StatusLines;
- char MainStColors = WHITE+(MAGENTA<<4);
- char SesStColors = WHITE+(BLUE<<4);
- #else
- int StatusLines = 0;
- #endif
-
- char *Screen;
- int ScreenSize;
- int SwapMode;
- #ifdef XMS
- unsigned int ScreenSizeK;
- #endif
-
- int Watchdog; /* Watch Dog off by default */
- int WDTick = 300*(1000 / MSPTICK); /* 5 minutes watchdog timer */
- int WDCurr = 300*(1000 / MSPTICK); /* Initial count down timer */
-
- /* This flag is set by setirq() if IRQ 8-15 is used, indicating
- * that the machine is a PC/AT with a second 8259 interrupt controller.
- * If this flag is set, the interrupt return code in pcgen.asm will
- * send an End of Interrupt command to the second 8259 as well as the
- * first.
- */
- int Isat;
-
- static char Ttbuf[BUFSIZ];
- static char Tsbuf[BUFSIZ];
- static int saved_break;
-
- int am_i_an_AT __ARGS((void));
-
-
- /* Keyboard input buffer */
- #define KBSIZE 256
- static struct {
- char buf[KBSIZE];
- char *wp;
- char *rp;
- int cnt;
- } Keyboard;
-
- #if !defined CPU286 && !defined CPU386 && !defined CPU486 && !defined CPU586
- int
- am_i_an_AT()
- {
- unsigned char *model_code = MK_FP(0xF000,0xFFFE);
-
- if(*model_code == 0xFC)
- return 1;
- else
- return 0;
- }
- #endif
-
- /* Following code from Doug Crompton */
- /* define the error messages for trapping disk problems
- */
- static char *crit_err_msg[] = {
- "write protect",
- "unknown unit",
- "not ready",
- "unknown command",
- "data error (CRC)",
- "bad request",
- "seek error",
- "unknown media type",
- "sector not found",
- "printer out of paper",
- "write fault",
- "read fault",
- "general failure",
- "reserved",
- "reserved",
- "invalid disk change"
- };
-
-
- int
- errhandler(int errval,int ax,int bp,int si)
- {
- char msg[80];
- unsigned di;
- int drive;
- int errorno;
-
- di= _DI;
-
- if (ax < 0)
- hardretn(3);
- drive = ax & 0x00FF;
- errorno = di & 0x00FF;
- sprintf(msg, "\r\nError: %s on drive %c\r\n$",
- crit_err_msg[errorno], 'A' + drive);
- bdosptr(0x09,msg,0);
- hardretn(3);
- return 0; /* to please the compiler */
- }
-
- int c_break(void) { /* ctrl-brk or ctrl-c handler */
- return 1;
- }
-
- #ifdef __BORLANDC__
- #undef fopen
- FILE _FAR *_Cdecl fopen(const char _FAR *__path, const char _FAR *__mode);
- #endif
-
- /* Called at startup time to set up console I/O, memory heap */
- void
- ioinit()
- {
-
- /* Fail all I/O errors */
- harderr(errhandler);
-
- /* Save these two file table entries for something more useful */
- fclose(stdaux);
- fclose(stdprn);
- setbuf(stdout,Tsbuf);
-
- Rawterm = fopen("con","wb");
- setbuf(Rawterm,Ttbuf);
- /* this breaks tab expansion so you must use ANSI or NANSI */
- ioctl(fileno(Rawterm), 1, (ioctl(fileno(Rawterm),0) & 0xff) | 0x20);
- saved_break = getcbrk();
- setcbrk(0);
- ctrlbrk(c_break);
-
- #ifdef MSDOS
- #if !defined CPU286 && !defined CPU386 && !defined CPU486 && !defined CPU586
- /* test to see if we're running on an AT class machine.
- * Set Isat flag accordingly - N1BEE
- */
- Isat = am_i_an_AT();
- #endif
- #endif
- Starttime = bioscnt();
- /* Link timer handler into timer interrupt chain */
- chtimer(btick);
-
- /* Find out what multitasker we're running under, if any */
- chktasker();
-
- /* Initialize keyboard queue */
- Keyboard.rp = Keyboard.wp = Keyboard.buf;
-
- /* Check for essential directories. */
- mkdir(LogsDir);
- mkdir(Fdir);
- mkdir(Spoolqdir);
- mkdir(Mailspool);
- mkdir(Mailqdir);
- mkdir(Routeqdir);
- #ifdef MAILBOX
- mkdir(Helpdir);
- mkdir(Signature);
- #endif
- #if defined NNTPS || defined NNTP
- mkdir(Newsdir);
- #endif
- }
-
- /* Called just before exiting to restore console state */
- void
- iostop()
- {
- struct iface *ifp,*iftmp;
- void (**fp)(void);
-
- setbuf(Rawterm,NULLCHAR);
- ioctl(fileno(Rawterm), 1, ioctl(fileno(Rawterm), 0) & 0xff & ~0x20);
- setcbrk(saved_break);
-
- for(ifp = Ifaces;ifp != NULLIF;ifp = iftmp){
- iftmp = ifp->next;
- if_detach(ifp);
- }
- /* Call list of shutdown functions */
- for(fp = Shutdown;*fp != NULLVFP;fp++){
- (**fp)();
- }
- }
- #ifdef SHELL
- /* Spawn subshell */
- int
- doshell(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- char *command;
- int ret;
- int OldWd;
-
- #ifdef MULTITASK
- if(Background) {
- if(!start_back())
- return -1;
- Nokeys++;
- free(mallocw(Minheap)); /* Force heap/core break to reserve a heap */
- } else
- #endif
- {
- OldWd = Watchdog; /* Save old watchdog state, and turn it off */
- Watchdog = 0; /* while shelled out */
- }
-
- if(argc == 1 || !stricmp(argv[1], "/c")) {
- if((command = getenv("COMSPEC")) == NULLCHAR)
- command = "COMMAND.COM";
- ret = spawnvp(P_WAIT,command,argv);
- } else {
- ret = spawnvp(P_WAIT,argv[1],(argv + 1));
- }
-
- #ifdef MULTITASK
- if(Background) {
- Nokeys--;
- stop_back();
- } else
- #endif
- {
- Watchdog = OldWd; /* Restore old watchdog state, */
- WDCurr = WDTick; /* and start with a fresh count */
- }
-
- /* Update index files - WG7J */
- UpdateIndex(NULL,0);
-
- return ret;
- }
- #endif
-
- #ifdef ALLCMD
- /* Spawn mailer as subshell */
- int
- dobmail(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- char *command;
- int ret;
- int OldWd;
-
- #ifdef MULTITASK
- if(Background) {
- if(!start_back())
- return -1;
- Nokeys++;
- free(mallocw(Minheap));
- } else
- #endif
- {
- OldWd = Watchdog; /* Save old watchdog state, and turn it off */
- Watchdog = 0; /* while shelled out */
- }
-
- if((command = getenv("MAILER")) == NULLCHAR)
- command = "BM.EXE";
- ret = spawnvp(P_WAIT,command,argv);
-
- #ifdef MULTITASK
- if(Background) {
- Nokeys--;
- stop_back();
- } else
- #endif
- {
- Watchdog = OldWd; /* Restore old watchdog state, */
- WDCurr = WDTick; /* and start with a fresh count */
- }
-
- /* Update index files - WG7J */
- UpdateIndex(NULL,0);
-
- smtptick(NULL); /* tickle smtp to send any mail */
- return ret;
- }
- #endif /*ALLCMD*/
-
- #ifdef MULTITASK
- /* if multitask mode is set - allow NOS and shell/mail to share system time */
- int dobackg(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Background,"Multitasking DOS Shell ",argc,argv);
- }
- #endif
-
- /* if watch-dog mode is set - make NOS reboot the system if it stalls */
- int dowatchdog(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Watchdog,"NOS Watch Dog",argc,argv);
- }
-
- /* Keyboard interrupt handler */
- void
- kbint()
- {
- int sig = 0;
- int c;
-
- #ifdef MULTITASK
- if(Background && Nokeys)
- return;
- #endif
-
- while((c = kbraw()) != -1 && Keyboard.cnt < KBSIZE){
- sig = 1;
- *Keyboard.wp++ = c;
- if(Keyboard.wp == &Keyboard.buf[KBSIZE])
- Keyboard.wp = Keyboard.buf;
- Keyboard.cnt++;
- }
- if(sig){
- psignal(&Keyboard,0);
- }
- }
- static int
- kbchar()
- {
- int i_state;
- char c;
-
- #ifdef MULTITASK
- if(Background && Nokeys)
- return -1;
- #endif
-
- i_state = dirps();
- while(Keyboard.cnt == 0)
- pwait(&Keyboard);
- Keyboard.cnt--;
- restore(i_state);
- c = *Keyboard.rp++;
- if(Keyboard.rp == &Keyboard.buf[KBSIZE])
- Keyboard.rp = Keyboard.buf;
- return uchar(c);
- }
- /* Flush the raw terminal output */
- void
- rflush()
- {
- fflush(Rawterm);
- }
-
- #ifdef MSDOS
- #ifdef ALLCMD
- struct funcstr {
- int fkey;
- char alloced;
- char *name;
- char *fvalue;
- };
-
- static struct funcstr DFAR fkeys[] = {
- 15,0,"Stab",NULLCHAR, /* tab + shift */
- 59,0,"F1",NULLCHAR, /* F1 */
- 60,0,"F2",NULLCHAR, /* F2 */
- 61,0,"F3",NULLCHAR, /* F3 */
- 62,0,"F4",NULLCHAR, /* F4 */
- 63,0,"F5",NULLCHAR, /* F5 */
- 64,0,"F6",NULLCHAR, /* F6 */
- 65,0,"F7",NULLCHAR, /* F7 */
- 66,0,"F8",NULLCHAR, /* F8 */
- 67,0,"F9",NULLCHAR, /* F9 */
- 68,0,"F10",NULLCHAR, /* F10 */
- 71,1,"home","\010", /* home*/
- 72,1,"up","\033[A", /* up arrow*/
- 73,1,"pgup","\025", /* pgup */
- 75,1,"left","\033[D", /* left arrow */
- 77,1,"right","\033[C", /* right arrow */
- 79,1,"end","\005", /* end */
- 80,1,"down","\033[B", /* down arrow */
- 81,1,"pgdn","\012", /* pgdn */
- 82,1,"ins","\001", /* ins */
- 83,1,"del","\177", /* del */
- 84,0,"SF1",NULLCHAR, /* F1 + shift*/
- 85,0,"SF2",NULLCHAR, /* F2 + shift*/
- 86,0,"SF3",NULLCHAR, /* F3 + shift*/
- 87,0,"SF4",NULLCHAR, /* F4 + shift*/
- 88,0,"SF5",NULLCHAR, /* F5 + shift*/
- 89,0,"SF6",NULLCHAR, /* F6 + shift*/
- 90,0,"SF7",NULLCHAR, /* F7 + shift*/
- 91,0,"SF8",NULLCHAR, /* F8 + shift*/
- 92,0,"SF9",NULLCHAR, /* F9 + shift*/
- 93,0,"SF10",NULLCHAR, /* F10 + shift*/
- 94,0,"CF1",NULLCHAR, /* F1 + control*/
- 95,0,"CF2",NULLCHAR, /* F2 + control*/
- 96,0,"CF3",NULLCHAR, /* F3 + control*/
- 97,0,"CF4",NULLCHAR, /* F4 + control*/
- 98,0,"CF5",NULLCHAR, /* F5 + control*/
- 99,0,"CF6",NULLCHAR, /* F6 + control*/
- 100,0,"CF7",NULLCHAR, /* F7 + control*/
- 101,0,"CF8",NULLCHAR, /* F8 + control*/
- 102,0,"CF9",NULLCHAR, /* F9 + control*/
- 103,0,"CF10",NULLCHAR, /* F10 + control*/
- 104,0,"AF1",NULLCHAR, /* F1 + alt*/
- 105,0,"AF2",NULLCHAR, /* F2 + alt*/
- 106,0,"AF3",NULLCHAR, /* F3 + alt*/
- 107,0,"AF4",NULLCHAR, /* F4 + alt*/
- 108,0,"AF5",NULLCHAR, /* F5 + alt*/
- 109,0,"AF6",NULLCHAR, /* F6 + alt*/
- 110,0,"AF7",NULLCHAR, /* F7 + alt*/
- 111,0,"AF8",NULLCHAR, /* F8 + alt*/
- 112,0,"AF9",NULLCHAR, /* F9 + alt*/
- 113,0,"AF10",NULLCHAR, /* F10 + alt*/
- 114,0,"Cprnt",NULLCHAR, /* PrtSc + ctl*/
- 117,0,"Cend",NULLCHAR, /* end + ctl */
- 118,0,"Cpgup",NULLCHAR, /* pgup + ctl */
- 119,0,"Chome",NULLCHAR, /* home + ctl */
- 132,0,"Cpgdn",NULLCHAR, /* pgdn + ctl */
- 133,0,"F11",NULLCHAR, /* F11 */
- 134,0,"F12",NULLCHAR, /* F12 */
- 135,0,"SF11",NULLCHAR, /* F11 + shift */
- 136,0,"SF12",NULLCHAR, /* F12 + shift */
- 137,0,"CF11",NULLCHAR, /* F11 + ctrl */
- 138,0,"CF12",NULLCHAR, /* F12 + ctrl */
- 139,0,"AF11",NULLCHAR, /* F11 + alt */
- 140,0,"AF12",NULLCHAR, /* F12 + alt */
- 0,0,NULL,NULLCHAR
- };
-
- char Leftover = 0;
- char *Nextkey;
- #endif /*ALLCMD*/
- #endif /*MSDOS*/
-
- /* Read characters from the keyboard, translating them to "real" ASCII.
- * If none are ready, block. The F-10 key is special; translate it to -2.
- * Modified for function key session switching, and command recall - WG7J
- */
- #ifdef ALLCMD
- int
- kbread()
- {
- #ifndef MSDOS
- int c;
- #else
- int c,i,j;
-
- if((c = Leftover) != 0) {
- Leftover = *Nextkey++;
- return c;
- }
- #endif MSDOS
- if((c = kbchar()) == 0){
- /* Lead-in to a special char */
- c = kbchar();
- if(Current == Command) { /* Check for command recall */
- if(c == 72) /* UP arrow */
- return UPARROW;
- if(c == 80) /* DOWN arrow */
- return DNARROW;
- }
- switch(c){
- case 3: /* NULL (bizzare!) */
- c = 0;
- break;
- case 68: /* F-10 key (used as command-mode escape) */
- if(fkeys[10].fvalue == NULLCHAR){
- c = -2;
- break;
- }
- default: /* Dunno what it is */
- #ifdef MSDOS
- if(c > 58 && c < 68) { /* F1 to F9 */
- if(fkeys[c-58].fvalue == NULLCHAR) {
- c = (c - 56) * -1; /* NO fkey defined - WG7J */
- break;
- }
- }
- for(i=0;(j = fkeys[i].fkey) != 0;i++)
- if(j == c) {
- Nextkey = fkeys[i].fvalue;
- if(Nextkey == NULLCHAR) {
- c = -1;
- return c;
- }
- /* If first char of fvalue is '~'
- * switch to command session.
- */
- if((c = *Nextkey++) == '~') {
- c = -2;
- Leftover = *Nextkey++;
- } else {
- if(c != 0)
- Leftover = *Nextkey++;
- #ifdef notdef
- if (c == '~') /* switch to command ses. on ~ char */
- c = -2; /* KN4L Change */
- #endif
- else
- c = -1;
- }
- return c;
- }
- #endif
- c = -1;
- }
- }
- return c;
- }
- #else /*ALLCMD*/
-
- int
- kbread()
- {
- int c;
-
- if((c = kbchar()) == 0){
- /* Lead-in to a special char */
- c = kbchar();
- if(Current == Command) { /* Check for command recall */
- if(c == 72) /* UP arrow */
- return UPARROW;
- if(c == 80) /* DOWN arrow */
- return DNARROW;
- }
- switch(c){
- case 3: /* NULL (bizzare!) */
- c = 0;
- break;
- case 68: /* F-10 key (used as command-mode escape) */
- c = -2;
- break;
- case 83: /* DEL key */
- c = 0x7f;
- break;
- default: /* Dunno what it is */
- if(c > 58 && c < 68) /* F1 to F9 */
- c = (c - 56) * -1;
- else
- c = -1;
- }
- }
- return c;
- }
-
- #endif /*ALLCMD*/
-
- #ifdef MSDOS
- #ifdef ALLCMD
- int
- dofkey(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- int c,i,j;
- char *q, *r;
- char str[100];
-
- if(argc == 1) {
- tputs("\n key num definition key num definition\n");
- for(i=0;fkeys[i].fkey != 0;i++) {
- char *s;
- if((s=fkeys[i].fvalue) == NULL)
- s = "";
- else {
- q=s;
- r=str;
- s=str;
- while(*q)
- if(*q < ' ') { /* This is ASCII dependent !! */
- *r++ = '^';
- *r++ = *q++ | 0x40;
- } else if (*q == '^') {
- *r++ = '^';
- *r++ = *q++;
- } else if (*q == '\177') {
- *r++ = '^';
- *r++ = '?';
- q++;
- } else {
- *r++ = *q++;
- }
- *r = '\0';
- }
- tprintf("%5.5s %3d %-20.20s ",fkeys[i].name,fkeys[i].fkey,s);
- if(i%2)
- tputc('\n');
- }
- tputs("\nusage: fkey <key number> [<value> | \"string\"]\n");
- return 0;
- }
-
- c = atoi(argv[1]);
- if(c == 0 || c > 255) {
- tputs("fkey number out of range.\n");
- return 1;
- }
-
- for(j = 0;(i = fkeys[j].fkey) != 0; j++)
- if(i == c)
- break;
-
- if(i == 0){
- tputs("fkey number not found\n");
- return 1;
- }
-
- if(argc == 2) {
- q = fkeys[j].fvalue;
- r = str;
- if(q == NULLCHAR)
- tprintf("fkey %d has no assigned value.\n",c);
- else {
- while(*q)
- if(*q < ' ') { /* This is ASCII dependent !! */
- *r++ = '^';
- *r++ = *q++ + 0x40;
- } else if (*q == '^') {
- *r++ = '^';
- *r++ = *q++;
- } else if (*q == '\177') {
- *r++ = '^';
- *r++ = '?';
- q++;
- } else
- *r++ = *q++;
- *r = '\0';
- tprintf("fkey = %s\n",str);
- }
- return 0;
- }
-
- if(argc == 3) {
- if(fkeys[j].alloced)
- fkeys[j].alloced = 0;
- else
- if(fkeys[j].fvalue != NULLCHAR)
- free(fkeys[j].fvalue);
-
- r = str;
- q = argv[2];
- while(*q){
- if(*q == '^'){ /* ^ gives control char next */
- q++;
- if(*q == '^') {
- *r++ = *q++; /* No, he wants a ^ */
- } else if (*q == '?') {
- *r++ = '\177';
- q++;
- } else {
- *r++ = *q++ & 0x1f;
- }
- } else
- *r++ = *q++;
- }
- *r = '\0';
- fkeys[j].fvalue = strdup(str);
- }
- return 0;
- }
- #endif /*ALLCMD*/
- #endif /*MSDOS*/
-
- /* Install hardware interrupt handler.
- * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
- * Note that bus line IRQ2 maps to IRQ9 on the AT
- */
- int
- setirq(irq,handler)
- unsigned irq;
- INTERRUPT (*handler)();
- {
- /* Set interrupt vector */
- if(irq < 8){
- setvect(8+irq,handler);
- } else if(irq < 16){
- Isat = 1;
- setvect(0x70 + irq - 8,handler);
- } else {
- return -1;
- }
- return 0;
- }
-
- /* Return pointer to hardware interrupt handler.
- * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
- */
- INTERRUPT
- (*getirq(irq))()
- unsigned int irq;
- {
- /* Set interrupt vector */
- if(irq < 8){
- return getvect(8+irq);
- } else if(irq < 16){
- return getvect(0x70 + irq - 8);
- } else {
- return NULLVIFP;
- }
- }
- /* Disable hardware interrupt */
- int
- maskoff(irq)
- unsigned irq;
- {
- if(irq < 8){
- setbit(0x21,(char)(1<<irq));
- } else if(irq < 16){
- irq -= 8;
- setbit(0xa1,(char)(1<<irq));
- } else {
- return -1;
- }
- return 0;
- }
- /* Enable hardware interrupt */
- int
- maskon(irq)
- unsigned irq;
- {
- if(irq < 8){
- clrbit(0x21,(char)(1<<irq));
- } else if(irq < 16){
- irq -= 8;
- clrbit(0xa1,(char)(1<<irq));
- } else {
- return -1;
- }
- return 0;
- }
- /* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
- int
- getmask(irq)
- unsigned irq;
- {
- if(irq < 8)
- return (inportb(0x21) & (1 << irq)) ? 0 : 1;
- else if(irq < 16){
- irq -= 8;
- return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
- } else
- return -1;
- }
- /* Called from assembler stub linked to BIOS interrupt 1C, called on each
- * hardware clock tick. Signal a clock tick to the timer process.
- */
- void
- ctick()
- {
- if(Watchdog)
- if(WDCurr-- == 0)
- sysreset();
- Tick++;
- #ifdef notdef
- Clock++; /* Keep system time */
- #endif
- psignal(&Tick,1);
- }
- /* Called from the timer process on every tick. NOTE! This function
- * can NOT be called at interrupt time because it calls the BIOS
- */
- void
- pctick()
- {
- long t;
- static long oldt; /* Value of bioscnt() on last call */
- static long days; /* # of times bioscnt() has rolled over */
-
- /* Update the time-since-boot */
- t = bioscnt();
-
- if(t < oldt)
- days++; /* bioscnt has rolled past midnight */
- oldt = t;
- Clock = (int32)((days * 0x1800b0L) + t - Starttime);
- }
-
- /* Set bit(s) in I/O port */
- void
- setbit(port,bits)
- unsigned port;
- char bits;
- {
- outportb(port,(char)inportb(port)|bits);
- }
- /* Clear bit(s) in I/O port */
- void
- clrbit(port,bits)
- unsigned port;
- char bits;
- {
- outportb(port,(char)(inportb(port) & ~bits));
- }
- /* Set or clear selected bit(s) in I/O port */
- void
- writebit(port,mask,val)
- unsigned port;
- char mask;
- int val;
- {
- register char x;
-
- x = inportb(port);
- if(val)
- x |= mask;
- else
- x &= ~mask;
- outportb(port,x);
- }
- /* Convert a pointer to a long integer */
- long
- ptol(p)
- void *p;
- {
- long x;
-
- x = FP_OFF(p);
- #ifdef LARGEDATA
- x |= (long)FP_SEG(p) << 16;
- #endif
- return x;
- }
- void *
- ltop(l)
- long l;
- {
- register unsigned int seg,offset;
-
- seg = (unsigned int)(l >> 16);
- offset = (unsigned int)l;
- return MK_FP(seg,offset);
- }
- #ifdef notdef /* Assembler versions in pcgen.asm */
- /* Multiply a 16-bit multiplier by an arbitrary length multiplicand.
- * Product is left in place of the multiplicand, and the carry is
- * returned
- */
- int16
- longmul(multiplier,n,multiplicand)
- int16 multiplier;
- int n; /* Number of words in multiplicand[] */
- register int16 *multiplicand; /* High word is in multiplicand[0] */
- {
- register int i;
- unsigned long pc;
- int16 carry;
-
- carry = 0;
- multiplicand += n;
- for(i=n;i != 0;i--){
- multiplicand--;
- pc = carry + (unsigned long)multiplier * *multiplicand;
- *multiplicand = pc;
- carry = pc >> 16;
- }
- }
- return carry;
- }
- /* Divide a 16-bit divisor into an arbitrary length dividend using
- * long division. The quotient is returned in place of the dividend,
- * and the function returns the remainder.
- */
- int16
- longdiv(divisor,n,dividend)
- int16 divisor;
- int n; /* Number of words in dividend[] */
- register int16 *dividend; /* High word is in dividend[0] */
- {
- /* Before each division, remquot contains the 32-bit dividend for this
- * step, consisting of the 16-bit remainder from the previous division
- * in the high word plus the current 16-bit dividend word in the low
- * word.
- *
- * Immediately after the division, remquot contains the quotient
- * in the low word and the remainder in the high word (which is
- * exactly where we need it for the next division).
- */
- unsigned long remquot;
- register int i;
-
- if(divisor == 0)
- return 0; /* Avoid divide-by-zero crash */
- remquot = 0;
- for(i=0;i<n;i++,dividend++){
- remquot |= *dividend;
- if(remquot == 0)
- continue; /* Avoid unnecessary division */
- #ifdef __TURBOC__
- /* Use assembly lang routine that returns both quotient
- * and remainder, avoiding a second costly division
- */
- remquot = divrem(remquot,divisor);
- *dividend = remquot; /* Extract quotient in low word */
- remquot &= ~0xffffL; /* ... and mask it off */
- #else
- *dividend = remquot / divisor;
- remquot = (remquot % divisor) << 16;
- #endif
- }
- return remquot >> 16;
- }
- #endif
-
- void
- sysreset()
- {
- void (*foo) __ARGS((void));
-
- foo = MK_FP(0xffff,0); /* FFFF:0000 is hardware reset vector */
- (*foo)();
- }
-
- void
- newscreen(sp)
- struct session *sp;
- {
- if(sp != NULLSESSION)
- sp->screen = callocw(1,sizeof(struct screen));
- }
-
- void
- freescreen(sp)
- struct session *sp;
- {
- if(sp == NULLSESSION || sp->screen == NULLSCREEN)
- return;
- #ifdef XMS
- if(sp->screen->stype == EMS_SWAP)
- effree(sp->screen->sv.ems.token);
- else
- #endif
- #ifdef XMS
- if(sp->screen->stype == XMS_SWAP && sp->screen->sv.handle != 0)
- Free_XMS(sp->screen->sv.handle);
- else
- #endif
- if(sp->screen->stype == FILE_SWAP && sp->screen->sv.fp != NULL)
- fclose(sp->screen->sv.fp);
- else if(sp->screen->stype == MEM_SWAP && sp->screen->sv.save != NULLCHAR)
- free(sp->screen->sv.save);
- free((char *)sp->screen);
- }
-
- #ifdef XMS
- /* Free XMS memory used for screen swapping.
- * Called right before exit().
- */
- void Free_Screen_XMS(void) {
- struct session *sp;
- int i;
-
- for(i=0,sp=Sessions;i < Nsessions;sp++,i++)
- if(sp->type != FREE && sp->screen->stype == XMS_SWAP && \
- sp->screen->sv.handle != 0)
- Free_XMS(sp->screen->sv.handle);
- }
- #endif
-
- extern int Numrows,Numcols;
-
- /* Save specified session screen and resume console screen */
- void
- swapscreen(old,new)
- struct session *old,*new;
- {
- struct text_info tr;
- #ifdef XMS
- long handle;
- struct XMS_Move X;
- #endif
-
- if(old == new)
- return; /* Nothing to do */
-
- fflush(Rawterm);
- gettextinfo(&tr);
-
- if(old != NULLSESSION){
- #ifdef SPLITSCREEN
- /* Save old screen */
- if(old->split){
- // window(1,1,Numcols,Numrows);
- }
- #endif
- #ifdef EMS
- if(old->screen->stype == EMS_SWAP) {
- set1eptr(old->screen->sv.ems.token,(void far**)&old->screen->sv.ems.save);
- if(old->screen->sv.ems.save != NULLCHAR)
- memcpy(old->screen->sv.ems.save,Screen,ScreenSize);
- } else
- #endif
- #ifdef XMS
- if(old->screen->stype == XMS_SWAP) {
- if(old->screen->sv.handle == 0)
- old->screen->sv.handle = Alloc_XMS(ScreenSizeK);
- if(old->screen->sv.handle != 0) {
- /* Now transfer to XMS */
- X.Length = (long) ScreenSize;
- X.SourceHandle = 0; /* Indicate conventional memory */
- X.SourceOffset = (long) Screen;
- X.DestHandle = old->screen->sv.handle;
- X.DestOffset = 0L;
- Move_XMS(&X);
- }
- } else
- #endif
- if(old->screen->stype == FILE_SWAP) {
- if(old->screen->sv.fp == NULL)
- old->screen->sv.fp = tmpfile();
- else
- fseek(old->screen->sv.fp,0L,0);
- if(old->screen->sv.fp != NULL){
- fwrite(Screen,ScreenSize,1,old->screen->sv.fp);
- }
- } else {
- if(old->screen->sv.save == NULLCHAR)
- old->screen->sv.save = malloc(ScreenSize);
- if(old->screen->sv.save != NULLCHAR){
- memcpy(old->screen->sv.save,Screen,ScreenSize);
- }
- }
- old->screen->row = tr.cury;
- old->screen->col = tr.curx;
- }
- if(new != NULLSESSION){
- /* Load new screen */
- if(new->screen->stype == UNKNOWN_SWAP) {
- /* A brand new screen */
- #ifdef EMS
- if(SwapMode == EMS_SWAP) {
- if(efmalloc(ScreenSize,&new->screen->sv.ems.token) != 0)
- new->screen->sv.ems.token = -1;
- new->screen->stype = EMS_SWAP;
- } else
- #endif
- #ifdef XMS
- if(SwapMode == XMS_SWAP) {
- new->screen->sv.handle = Alloc_XMS(ScreenSizeK);
- new->screen->stype = XMS_SWAP;
- } else
- #endif
- if(SwapMode == FILE_SWAP)
- new->screen->stype = FILE_SWAP;
- else
- new->screen->stype = MEM_SWAP;
-
- #ifdef SPLITSCREEN
- if(new->split){
- new->tsavex = 1;
- new->tsavey = 1;
- new->bsavex = 1;
- new->bsavey = Numrows-1;
- /* The output window */
- window(1,1+StatusLines,Numcols,Numrows);
- textattr(SplitColors);
- clrscr(); /* Start with a fresh slate */
- cputs("_\b");
-
- /* The input window */
- window(1,1+StatusLines,Numcols,Numrows-2);
- textattr(MainColors);
- clrscr(); /* Start with a fresh slate */
- cputs("_\b");
- } else
- #endif
- {
- /* leave room for the status line */
- window(1,1+StatusLines,Numcols,Numrows);
- clrscr(); /* Start with a fresh slate */
- }
- } else {
- #ifdef SPLITSCREEN
- if(new->split){
- window(1,1+StatusLines,Numcols,Numrows-2);
- textattr(MainColors);
- } else
- #endif
- {
- window(1,1+StatusLines,Numcols,Numrows);
- }
- #ifdef EMS
- if(new->screen->stype == EMS_SWAP &&
- (int)new->screen->sv.ems.token != -1) {
- /* Get the text from EMS into screen buffer */
- set1eptr(new->screen->sv.ems.token,(void far**)&new->screen->sv.ems.save);
- memcpy(Screen,new->screen->sv.ems.save,ScreenSize);
- } else
- #endif
- #ifdef XMS
- if(new->screen->stype == XMS_SWAP &&
- new->screen->sv.handle) {
- /* Get the text from XMS into screen buffer */
- X.Length = (long) ScreenSize;
- X.SourceHandle = new->screen->sv.handle;
- X.SourceOffset = 0L;
- X.DestHandle = 0L; /* Indicate conventional memory */
- X.DestOffset = (long) Screen;
- Move_XMS(&X);
- } else
- #endif
- if(new->screen->stype == FILE_SWAP &&
- new->screen->sv.fp) {
- fseek(new->screen->sv.fp,0L,0);
- fread(Screen,ScreenSize,1,new->screen->sv.fp);
-
- /* Not closing is a little faster,
- * but takes more resources
- * while the session is active - WG7J
- */
- fclose(new->screen->sv.fp);
- new->screen->sv.fp = NULLFILE;
-
- } else if(new->screen->stype == MEM_SWAP &&
- new->screen->sv.save) {
- memcpy(Screen,new->screen->sv.save,ScreenSize);
- /* Free the memory (saves 4K on a continuous basis) */
- free(new->screen->sv.save);
- new->screen->sv.save = NULLCHAR;
- } else
- /* Somehow, we couldn't save the old screen */
- clrscr();
- gotoxy(new->screen->col,new->screen->row);
- }
- }
- alert(Display,1); /* Wake him up */
- }
-
- void
- display(i,v1,v2)
- int i;
- void *v1;
- void *v2;
- {
- int c;
- struct session *sp;
-
- /* This is very tricky code. Because the value of "Current" can
- * change any time we do a pwait, we have to be careful to detect
- * any change and go back and start again.
- */
- for(;;){
- sp = Current;
-
- if(sp->morewait){
- pwait(&sp->row);
- if(sp != Current || sp->row <= 0){
- /* Current changed value, or the user
- * hasn't really hit a key
- */
- continue;
- }
- /* Erase the prompt */
- if(StatusLines)
- cputs("\r \r");
- else
- fprintf(Rawterm,"\r \r");
- }
- sp->morewait = 0;
- if((c = rrecvchar(sp->output)) == -1){
- /* the alert() in swapscreen will cause this to
- * return -1 when current changes
- */
- pwait(NULL); /* Prevent a nasty loop */
- continue;
- }
- if(StatusLines || sp->split){
- if(c == 0x0a){
- cputs(Eol);
- clreol();
- } else if(c == 0x09) /* TAB */
- do putch(' '); while(wherex() % 8 != 1);
- else
- putch(c);
- } else {
- putc(c,Rawterm);
- }
- /* Fix by Ron Murray, vk6zjm */
- if(sp->record != NULLFILE) { /* Don't save CR if ascii mode */
- if(c == '\r' || c == '\n')
- fflush(sp->record);
- if(c != '\r' || sockmode(sp->output, -1) != SOCK_ASCII)
- putc(c,sp->record);
- }
- #ifdef notdef
- if(sp->record != NULLFILE)
- putc(c,sp->record);
- #endif
- if(sp->flowmode && c == '\n' && --sp->row <= 0){
- if(StatusLines)
- cputs("--More--");
- else
- fprintf(Rawterm,"--More--");
- sp->morewait = 1;
- }
- }
- }
-
- /* Return time since startup in milliseconds. If the system has an
- * 8254 clock chip (standard on ATs and up) then resolution is improved
- * below 55 ms (the clock tick interval) by reading back the instantaneous
- * value of the counter and combining it with the global clock tick counter.
- * Otherwise 55 ms resolution is provided.
- *
- * Reading the 8254 is a bit tricky since a tick could occur asynchronously
- * between the two reads. The tick counter is examined before and after the
- * hardware counter is read. If the tick counter changes, try again.
- * Note: the hardware counter counts down from 65536.
- */
- int32
- msclock()
- {
- int32 hi;
- int16 lo;
- int16 count[4]; /* extended (48-bit) counter of timer clocks */
-
- if(!Isat)
- return Clock * MSPTICK;
-
- do {
- hi = Clock + Tick;
- lo = clockbits();
- } while(hi != Clock + Tick); /* Make sure a tick didn't just occur */
-
- count[0] = 0;
- count[1] = hi >> 16;
- count[2] = hi;
- count[3] = -lo;
- longmul(11,4,count); /* The ratio 11/13125 is exact */
- longdiv(13125,4,count);
- return ((long)count[2] << 16) + count[3];
- }
- /* Return clock in seconds */
- int32
- secclock()
- {
- int32 hi;
- int16 lo;
- int16 count[4]; /* extended (48-bit) counter of timer clocks */
-
- if(!Isat)
- return Clock * MSPTICK / 1000L;
-
- do {
- hi = Clock + Tick;
- lo = clockbits();
- } while(hi != Clock + Tick); /* Make sure a tick didn't just occur */
-
- count[0] = 0;
- count[1] = hi >> 16;
- count[2] = hi;
- count[3] = -lo;
- longmul(11,4,count); /* The ratio 11/13125 is exact */
- longdiv(13125,4,count);
- longdiv(1000,4,count);
- return ((long)count[2] << 16) + count[3];
- }
-
- int
- doisat(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Isat,"AT/386 mode",argc,argv);
- }
-
- /* Directly read BIOS count of time ticks. This is used instead of
- * calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
- * wich resets the midnight overflow flag, losing days on the clock.
- */
- long
- bioscnt()
- {
- if(Mtasker < 5) { /* Read direct except under OS/2 or DPMI */
- int i_state;
- long rval;
-
- i_state = dirps();
- rval = * (long far *)MK_FP(0x40,0x6c);
- restore(i_state);
- return rval;
- } else { /* Use BIOS call under OS/2 or DPMI */
- return(biostime(0,0L));
- }
- }
-
- /* same as getenv(), but return "" instead of NULL when it does not exist */
- char *getnenv (name)
- char *name;
- {
- char *rv;
-
- if ((rv = getenv(name)) == NULL)
- rv = ""; /* NULL replaced by "" */
-
- return rv;
- }
-
- #ifdef STATUSWIN
-
- void StatusLine1(void);
-
- /* First line. Global information */
- void StatusLine1() {
-
- struct session *sp;
- int len=0,s,r,t;
- char *cp;
-
- extern int ConvUsers,ConvHosts,BbsUsers,FwdUsers,FtpUsers,SmtpUsers;
- #ifdef MAILFOR
- extern int Mail_Received; /* see mailfor.c */
-
-
- /* PE1DGZ: Show blinking 'MAIL' if unread mail is present */
- if(Mail_Received) {
- textattr(MainStColors | 0x80);
- len += cputs("MAIL ");
- }
- #endif
-
- /* Set the colors */
- textattr(MainStColors);
-
- #ifdef MSDOS
- #if __BORLANDC__ >= 0x0400
- {
- char buf[9];
-
- _strtime(buf); /* This only exists in bc3.0 and up */
- buf[5] = ' ';
- buf[6] = '\0';
- len+=cputs(buf);
- }
- #endif
- #endif
-
- len+=cprintf("%5.5lu/%-6.6lu"
- #ifdef CONVERS
- " CONV=%d LNKS=%d"
- #endif
- #ifdef MAILBOX
- " BBS=%d"
- #ifdef MBFWD
- " FWD=%d"
- #endif
- #endif
- #ifdef FTPSERVER
- " FTP=%d"
- #endif
- #ifdef SMTPSERVER
- " SMTP=%d"
- #endif
- " Ses:",
-
- Localheap(),coreleft()
- #ifdef CONVERS
- ,ConvUsers, ConvHosts
- #endif
- #ifdef MAILBOX
- ,BbsUsers
- #ifdef MBFWD
- ,FwdUsers
- #endif
- #endif
- #ifdef FTPSERVER
- ,FtpUsers
- #endif
- #ifdef SMTPSERVER
- ,SmtpUsers
- #endif
- );
-
- /* Print all active sessions . Modified from TNOS
- * Calculate how much room there is left on the line
- */
-
- for(sp=Sessions; sp < &Sessions[Nsessions];sp++) {
- // if(Numcols - len < 3)
- // break;
- if(sp->type == FREE || sp->type == COMMAND || sp->type == TRACESESSION)
- continue;
-
- /* if there is data waiting, blink the session number */
- r = socklen(sp->output,1);
- textattr ( (r) ? MainStColors | 0x80 : MainStColors);
- len+=cprintf (" %d", sp->num);
- }
- textattr(MainStColors); /* In case blinking was on! */
- clreol();
- }
-
- #ifdef MAILBOX
- char *StBuf2; /* allocated in main.c */
- int StLen2;
-
- void StatusLine2(void);
-
- void StatusLine2() {
- struct mbx *m;
- char *cp;
- int len;
-
- cp = StBuf2+StLen2;
- *cp = '\0';
- for(m=Mbox;m;m=m->next) {
- if((len = strlen(m->name)) != 0 && (len < Numcols-(cp-StBuf2)-4)) {
- *cp++ = ' ';
- if(m->sid & MBX_SID)
- *cp++ = '*'; /* Indicate a bbs */
- else switch(m->state) {
- case MBX_GATEWAY:
- *cp++ = '!';
- break;
- case MBX_READ:
- case MBX_SUBJ:
- case MBX_DATA:
- *cp++ = '#';
- break;
- case MBX_UPLOAD:
- case MBX_DOWNLOAD:
- case MBX_XMODEM_RX:
- case MBX_XMODEM_TX:
- *cp++ = '=';
- break;
- case MBX_SYSOPTRY:
- case MBX_SYSOP:
- *cp++ = '@';
- break;
- case MBX_CONVERS:
- case MBX_CHAT:
- *cp++ = '^';
- case MBX_CMD:
- *cp++ = ' '; /* To keep things aligned nicely */
- break;
- default:
- *cp++ = '?';
- break;
- }
- strcpy(cp,m->name);
- cp += len;
- }
- }
- cputs(StBuf2);
- clreol();
- }
- #endif /* MAILBOX */
-
- char *StBuf3; /* allocated in main.c */
- int StLen3;
- void StatusLine3(void);
-
- /* The session dependent data */
- void StatusLine3() {
- char *cp;
- int s,t,SesType;
- struct usock *up;
-
- static struct session *MyCurrent;
- static int SesNameLen;
- static int SockStatus,SockName,SesData;
-
- /* Set the colors */
- textattr(SesStColors);
-
- /* Next line. Session specific information */
- if(MyCurrent != Current) {
- /* Keep track of the current session */
- MyCurrent = Current;
- SesType = MyCurrent->type;
- /* Remember to offset for "\r\n" at start of buffer ! */
- SesNameLen = 2;
- SesNameLen+=sprintf(StBuf3+SesNameLen,"%d %s:",
- MyCurrent->num,Sestypes[SesType]);
-
- /* We can't show network socket data until socket is valid ! */
- SesData = SockName = 0;
-
- SockStatus = 1; /* Show socket status by default */
- if(SesType == COMMAND || SesType == TRACESESSION) {
- // if(Command->curdirs)
- // sprintf(StBuf3+SesNameLen, "%-30.30s",Command->curdirs->dir);
- SockStatus = 0; /* Don't show socket name and ses data */
-
- } else if(SesType == MORE ||
- SesType == REPEAT ||
- SesType == LOOK) {
- sprintf(StBuf3+SesNameLen," %-20.20s",MyCurrent->name);
- SockStatus = 0; /* Don't show socket name and ses data */
- }
- }
- /* Only if this is a session with a network socket do we show the status */
- if(SockStatus) {
- if(!SockName && (s=MyCurrent->s) != -1) {
- int i;
- struct sockaddr fsocket;
-
- /* The session now has a valid network socket.
- * Go get the name, and pointer.
- */
- if(getpeername(s,(char *)&fsocket,&i) == -1)
- cp = "";
- else cp = psocket(&fsocket);
- SesNameLen+=sprintf(StBuf3+SesNameLen," %-18.18s TxQ ",cp);
- SockName = SesData = 1;
- }
- /* We have the socket name, now go print the socket session data */
- if(SockName) {
- /* Some sessions keep hanging on to their network socket
- * until the use hits return to close the session !
- * Others will delete it sooner...
- */
- if((s=MyCurrent->s) != -1 && ((cp=sockstate(s))!= NULL) ) {
- /* Network socket for session still valid */
- t = socklen(s,1);
- StLen3 = SesNameLen +
- sprintf(StBuf3+SesNameLen,"%4.4d St: %-12.12s",t,cp);
- } else {
- SesData = 0; /* Don't print rest of line 3 ! */
- sprintf(StBuf3+SesNameLen-4," LIMBO !");
- }
- /* If the socket is still valid, print some data */
- if(SesData) {
- up = itop(s);
- switch(up->type) {
- case(TYPE_TCP):
- {
- struct tcb *tcb = up->cb.tcb;
- sprintf(StBuf3+StLen3,
- " T: %5.5ld/%-5.5ld ms",
- (long)read_timer(&tcb->timer),
- (long)dur_timer(&tcb->timer));
- }
- break;
- #ifdef AX25
- case(TYPE_AX25I):
- {
- struct ax25_cb *axp = up->cb.ax25;
- sprintf(StBuf3+StLen3,
- " T1: %5.5ld/%5.5ld ms",
- (long)read_timer(&axp->t1),
- (long)dur_timer(&axp->t1));
- }
- break;
- #endif
- #ifdef NETROM
- case(TYPE_NETROML4):
- {
- struct nr4cb *cb = up->cb.nr4;
- sprintf(StBuf3+StLen3,
- " T: %5.5ld/%5.5ld ms",
- (long)read_timer(&cb->tcd),
- (long)dur_timer(&cb->tcd));
- }
- break;
- #endif
- }
- }
- }
- }
- cputs(StBuf3);
- clreol();
- }
-
- /* Build the status window on the screen - WG7J */
- void UpdateStatus() {
-
- if(!StatusLines)
- return;
-
- #ifdef MULTITASK
- /* if we are shelled out with multi-task on, do not update the status */
- if(Background && Nokeys)
- return;
- #endif
-
-
- {
- struct text_info ti;
-
- /* get the current output context */
- gettextinfo(&ti);
-
- /* create the window */
- window(1,1,Numcols,StatusLines);
-
- StatusLine1(); /* Global system status */
- if(StatusLines > 1)
- #ifdef MAILBOX
- StatusLine2(); /* Mailbox user status */
- if(StatusLines > 2)
- #endif
- StatusLine3(); /* Session dependent status */
-
- /* restore the previous output context */
- window((int)ti.winleft,(int)ti.wintop,
- (int)ti.winright,(int)ti.winbottom);
- textattr(ti.attribute);
- gotoxy(ti.curx,ti.cury);
- }
- }
-
- #endif /* STATUSWIN */
-
-